package edu.ilstu.mind.ise.ccp.impl.queued;

import java.util.HashMap;
import java.util.Map;

import edu.ilstu.mind.ise.ccp.CentralControlProcessor;
import edu.ilstu.mind.ise.ccp.logger.Logger;
import edu.ilstu.mind.ise.ccp.message.MessageSender;
import edu.ilstu.mind.ise.ccp.message.hashmap.HashMapMutableMessageFactory;
import edu.ilstu.mind.ise.ccp.mindmodule.MindModule;
import edu.ilstu.mind.ise.ccp.module.Module;

public class QueuedCentralControlProcessor implements CentralControlProcessor {

	private Logger logger;
	private MindModule mindModule;
	private Map<String, QueuedModuleThread> moduleThreads = new HashMap<String, QueuedModuleThread>();
	private QueuedMessageRouter messageRouter;
	
	@Override
	public void setLogger(Logger logger) {
		this.logger = logger;
	}
	
	@Override
	public void setMindModule(MindModule mindModule) {
		this.mindModule = mindModule;
	}

	@Override
	public void addModule(String name, Module module) {
		// make sure module does not already exist
		if (moduleThreads.containsKey(name)) {
			throw new IllegalArgumentException("Cannot add multiple modules with the same name <" + name + ">");
		}
		// create module thread and add it to the module thread map
		moduleThreads.put(name, new QueuedModuleThread(module));
	}

	@Override
	public void init() {
		logger.info("Initializing " + getClass().getSimpleName());
		
		// verify setters were called
		if (mindModule == null) {
			throw new IllegalArgumentException("mindModule cannot be null");
		}
		if (moduleThreads.size() == 0) {
			throw new IllegalArgumentException("Number of modules must be greater than 0");
		}
		
		// create the message router
		messageRouter = new QueuedMessageRouter(mindModule, moduleThreads);

		// create the message sender
		MessageSender messageSender = new QueuedMessageSender(messageRouter);

		// start the message router thread
		messageRouter.start();
		
		// initialize the mind module
		mindModule.setMessageFactory(new HashMapMutableMessageFactory());
		mindModule.setMessageSender(messageSender);
		mindModule.init();
		
		// start each module thread
		for(Map.Entry<String, QueuedModuleThread> entry : moduleThreads.entrySet()) {
			// get needed vars out of entry
			String moduleName = entry.getKey();
			QueuedModuleThread moduleThread = entry.getValue();
			Module module = moduleThread.getModule();
			
			// set message factory
			module.setMessageFactory(new HashMapMutableMessageFactory(moduleName));
			// set message sender
			module.setMessageSender(messageSender);
			// initialize the module
			module.init();
			// start the module thread
			moduleThread.start();
		}
		
		logger.info("Initialized");
	}
}